#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "UVisDataSubscriber.h"
#include "UVisDataProvider.h"
#include "FVisDataCenter.generated.h"

class UVisDataSubscriber;
class IVisDataSubscriber;

USTRUCT(BlueprintType)
struct FSubscriberInfo
{
	GENERATED_BODY()

	UVisDataSubscriber* subscriber;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ClampMin = "0", ClampMax = "512"))
	int subscriberDataIndex;
};

USTRUCT(BlueprintType)
struct FSubscriberActorInfo : public FSubscriberInfo
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	AActor* subscriberActor;
};

USTRUCT(BlueprintType)
struct FVisData
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FName name;
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FGuid guid;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	AActor* providerActor;
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	int poviderDataIndex;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TArray<FSubscriberActorInfo> subscriberActors;
};

USTRUCT(BlueprintType)
struct FFloatVisData : public FVisData
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float initialValue;
};

USTRUCT(BlueprintType)
struct FIntVisData : public FVisData
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	int initialValue;
};

template<typename DataT,typename CallbackEventT>
requires std::derived_from<CallbackEventT, TMulticastDelegate<void(DataT)>>
class SIMUVISUALIZER_API FVisDataPair
{
public:
	FName name;
	FGuid guid;

	UTypedDataProvider_Internal<DataT, CallbackEventT>* provider;
	TArray<UTypedDataSubscriber_Internal<DataT, CallbackEventT>*> subscribers;
public:
	void BindProviderSubscriber();
};

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class SIMUVISUALIZER_API UFVisDataCenter : public UActorComponent
{
	GENERATED_BODY()
public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data ")
	TArray<FFloatVisData> floatDataInfo;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
	TArray<FIntVisData> intData;
private:
	TArray<FVisDataPair<float, FOnFloatProvided>> floatDataPairs_;
	TArray<FVisDataPair<int, FOnIntProvided>> intDataPairs_;
public:	
	// Sets default values for this component's properties
	UFVisDataCenter();

	void BuildDataConnections();

protected:
	// Called when the game starts
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
};
